package com.bullardev.xldatacluster.providers;

import java.io.StringWriter;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;

import com.bullardev.xldatacluster.providers.webservice.lists.ListsSoap;
import com.bullardev.xldatacluster.providers.webservice.lists.
                        GetListCollectionResponse.GetListCollectionResult;
import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;

/**
 *
 * @author ibm
 *
 */
public final class ReadMetaData {

    /**
     *
     */
    private List<String> columnNames = new ArrayList<String>();
    /**
     *
     */
    private List<String> columnLabels = new ArrayList<String>();
    /**
     *
     */
    private List<String> columnTypes = new ArrayList<String>();
    /**
     *
     */
    private List<String> columnOrders = new ArrayList<String>();

    /**
     * Default constructor.
     */
    private ReadMetaData() {

    }

    /**
     * @return ReadMetaData instance of this class
     */
    public static ReadMetaData getInstance() {
        return new ReadMetaData();
    }
    /**
     *
     * @param port ListsSoap port
     * @param connectionProps Connection properties bag
     * @throws Exception on error
     */
    //public static void main(final String[] args) throws Exception {
      public void getMetaData(final ListsSoap port,
                      final Properties connectionProps) throws Exception {


        Authenticator.setDefault(new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                        connectionProps.getProperty("USER_NAME"),
                         connectionProps.getProperty("PASSWORD").toCharArray());
            }
        });

        String listID =
                getListID(connectionProps.getProperty("LIST_NAME"), port);

        //System.out.println("List ID is :" + listID);
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = dbf.newDocumentBuilder();
        String wsdlUrl = (String) connectionProps.get("WSDL_URL");
        String prefix = wsdlUrl.substring(0, wsdlUrl.lastIndexOf('/') + 1);

        String suffix = "&XMLDATA=TRUE";
        if ("Tasks".equalsIgnoreCase(connectionProps.
                            getProperty("LIST_NAME"))) {
            suffix = "&Query=*&XMLDATA=TRUE";
        }
        Document doc = docBuilder.parse(prefix + "owssvr.dll?"
                + "Cmd=Display&"
                + "List=" + listID + suffix);
        System.out.println(xmlToString(doc));
        NodeList attributeTags = doc.getElementsByTagName("s:AttributeType");
        for (int j = 0; j < attributeTags.getLength(); j++) {
            NamedNodeMap attribs = attributeTags.item(j).getAttributes();
            for (int i = 0; i < attribs.getLength(); i++) {
                String nodeVal = attribs.item(i) + "";
                if (nodeVal.startsWith("rs:name=")) {
                    columnLabels.add(nodeVal.substring(nodeVal.indexOf('=') + 2,
                                                         nodeVal.length() - 1));
                } else if (nodeVal.startsWith("rs:number=")) {
                    columnOrders.add(nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1));
                } else if (nodeVal.startsWith("name=")) {
                    columnNames.add(nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1));
                }
            }
        }
        NodeList dataTypeTags = doc.getElementsByTagName("s:datatype");
        for (int j = 0; j < attributeTags.getLength(); j++) {
            NamedNodeMap dataTypes = dataTypeTags.item(j).getAttributes();
            for (int i = 0; i < dataTypes.getLength(); i++) {
                String dataTypesAttribs = dataTypes.item(i) + "";
                if (dataTypesAttribs.startsWith("dt:type=")) {
                    columnTypes.add(dataTypesAttribs.substring(
                                    dataTypesAttribs.indexOf('=') + 2,
                                        dataTypesAttribs.length() - 1));
                }
            }
        }

        System.out.println(columnNames);
        System.out.println(columnTypes);
        System.out.println(columnOrders);
    }

    /**
     * Method to extract list ID from given list name.
     * @param listName Name of the list
     * @param port ListsSoap port
     * @return ID of the list
     */
    private String getListID(final String listName,
                                        final ListsSoap port) {
        GetListCollectionResult res = port.getListCollection();
        Object resR = res.getContent().get(0);

        if (resR != null && resR instanceof ElementNSImpl) {
            ElementNSImpl node = (ElementNSImpl) resR;
            //Document doc = node.getOwnerDocument();
            //System.out.println(xmlToString(doc));
            NodeList nodesList = node.getElementsByTagName("List");
            if (nodesList.getLength() > 0) {
                for (int i = 0; i < nodesList.getLength(); i++) {
                    NamedNodeMap tempAttrib = nodesList.item(i).getAttributes();
                    String listTitle = "";
                    String listID = "";
                    for (int j = 0; j < tempAttrib.getLength(); j++) {
                        String nodeVal = tempAttrib.item(j) + "";
                        if (nodeVal.startsWith("Title=")) {
                            listTitle = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        } else if (nodeVal.startsWith("ID=")) {
                            listID = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        }
                        if (listTitle.equals(listName)
                                      &&  listID.length() > 0) {
                            return listID;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     *
     * @return List of sharepoint column labels
     */
    public List<String> getColumnLabels() {
        return columnLabels;
    }

    /**
    *
    * @return List of sharepoint column names
    */
   public List<String> getColumnNames() {
       return columnNames;
   }

    /**
     *
     * @return  List of sharepoint column types
     */
    public List<String> getColumnTypes() {
        return columnTypes;
    }

    /**
     *
     * @return List of sharepoint column order
     */
    public List<String> getColumnOrders() {
        return columnOrders;
    }
    /**
     * Creates a string from an XML file with start and end indicators.
     * @param docToString document to convert
     * @return string of the xml document
     */
    public static String xmlToString(final Document docToString) {
        String returnString = "\n-------------- XML START --------------\n";
        try {
            //create string from xml tree
            //Output the XML
            //set up a transformer
            TransformerFactory transfac = TransformerFactory.newInstance();
            Transformer trans;
            trans = transfac.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperty(OutputKeys.INDENT, "yes");
            StringWriter sw = new StringWriter();
            StreamResult streamResult = new StreamResult(sw);
            DOMSource source = new DOMSource(docToString);
            trans.transform(source, streamResult);
            String xmlString = sw.toString();
            //print the XML
            returnString = returnString + xmlString;
        } catch (TransformerException ex) {
            ex.printStackTrace();
        }
        returnString = returnString + "-------------- XML END --------------";
        return returnString;
    }

}
